﻿using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

// ReSharper disable NonReadonlyMemberInGetHashCode
// ReSharper disable BaseObjectGetHashCodeCallInGetHashCode

namespace SW.DDD.Domain
{
    /// <summary>
    /// 实体简单实现
    /// </summary>
    /// <typeparam name="TKey">实体键类型</typeparam>
    public abstract class Entity<TKey> : IEntity<TKey> 
        where TKey : notnull
    {
        [Key]
        public abstract TKey Id { get; protected set; }

        private readonly Queue<IDomainEvent<IEntity<TKey>>> _events = new Queue<IDomainEvent<IEntity<TKey>>>();

        public IReadOnlyCollection<IDomainEvent<IEntity>> Events => _events;

        protected void EnqueueEvent(IDomainEvent<IEntity<TKey>> @event) => _events.Enqueue(@event);

        public IEnumerable<IDomainEvent<IEntity>> DequeenAllEvent()
        {
            while (_events.Count != 0)
            {
                yield return _events.Dequeue();
            }
        }

        public virtual bool IsTransient() => EqualityComparer<TKey>.Default.Equals(Id, default);

        public override int GetHashCode()
        {
            return IsTransient() ? base.GetHashCode() : Id.GetHashCode();
        }

        public override bool Equals(object? obj)
        {
            if(obj == null || obj.GetType() != GetType()) return false;

            if(IsTransient() || ((Entity<TKey>)obj).IsTransient())
                return false;

            return EqualityComparer<TKey>.Default.Equals(Id, ((Entity<TKey>)obj).Id);
        }

        public static bool operator==(Entity<TKey>? left, Entity<TKey>? right)
        {
            return left?.Equals(right) ?? Equals(right, null);
        }

        public static bool operator!=(Entity<TKey>? left, Entity<TKey>? right)
        {
            return !(left == right);
        }

        public override string ToString() => $"{GetType().Name}(Id={Id})";
    }
}
